<template>
  <div class="zzpzhuisu-container">
    <div id="x6-container" class="x6-container"></div>
    <teleport-container />
    <el-button
      circle
      class="search-btn"
      :icon="Search"
      size="large"
      type="primary"
      @click="showChaxunDialog"
    />
    <el-button
      circle
      class="plus-btn"
      :icon="Plus"
      size="large"
      type="primary"
      @click="plus"
    />
    <el-button
      circle
      class="sub-btn"
      :icon="Minus"
      size="large"
      type="primary"
      @click="sub"
    />
    <ChaxunDialog
      ref="chaxunDialog"
      @search-dialog-callback="searchDialogCallback"
    />
  </div>
</template>

<script setup>
  import { Search, Plus, Minus } from '@element-plus/icons-vue'
  import ChaxunDialog from './modules/ChaxunDialog.vue'
  import { Graph } from '@antv/x6'
  import { register, getTeleport } from '@antv/x6-vue-shape'
  import WorkInProgress from './modules/WorkInProgress.vue'
  import Material from './modules/Material.vue'
  import InspectionApplication from './modules/InspectionApplication.vue'
  import InspectionSheet from './modules/InspectionSheet.vue'
  import Product from './modules/Product.vue'
  import WorkReport from './modules/WorkReport.vue'
  const VIEW_HEIGHT = 220,
    VIEW_WIDTH = 400,
    SPACE_DISTANCE = 50
  let Y_node_Map = {},
    nodeList = []
  let mWidth = 1000,
    mHeight = 600,
    midY = 50,
    midX = 50,
    mGraph = null,
    zoom = 1

  register({
    shape: 'work-in-progress',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: WorkInProgress,
  })
  register({
    shape: 'material',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: Material,
  })
  register({
    shape: 'inspection-application',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: InspectionApplication,
  })
  register({
    shape: 'inspection-sheet',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: InspectionSheet,
  })
  register({
    shape: 'product',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: Product,
  })
  register({
    shape: 'workReport',
    width: VIEW_WIDTH,
    height: VIEW_HEIGHT,
    component: WorkReport,
  })

  const plus = () => {
    zoom += 0.1
    mGraph.zoomTo(zoom)
  }
  const sub = () => {
    zoom -= 0.1
    mGraph.zoomTo(zoom)
  }
  const TeleportContainer = getTeleport()
  const chaxunDialog = ref()
  const showChaxunDialog = async () => {
    chaxunDialog.value.toOpenChaxunDialog()
  }

  onMounted(() => {
    const dom = document.querySelector('#x6-container')
    mWidth = dom.clientWidth
    mHeight = dom.clientHeight
    midX = SPACE_DISTANCE
    midY = mHeight / 2
    initErGraph()
  })
  const initErGraph = () => {
    Y_node_Map = {}
    nodeList = []
    mGraph = new Graph({
      container: document.querySelector('#x6-container'),
      background: '#F2F7FA',
      width: mWidth,
      height: mHeight,
      panning: true,
      mousewheel: {
        enabled: true,
        modifiers: ['ctrl', 'meta'],
      },
    })
  }
  const searchDialogCallback = (selectData) => {
    mGraph.resetCells([])
    nextTick(() => {
      selectData = { ...selectData, isSelf: true }
      addWorkReport([selectData])
    })
  }
  const setNodeMap = (node) => {
    const mY = node.position().y
    if (Y_node_Map[mY]) {
      const mIndex = Y_node_Map[mY].findIndex((fNode) => {
        return fNode.position().x >= node.position().x
      })
      if (mIndex < 0) {
        Y_node_Map[mY].push(node)
      } else {
        if (
          Y_node_Map[mY][mIndex].position().x <
          node.position().x + VIEW_WIDTH + SPACE_DISTANCE
        ) {
          for (let k = mIndex; k < Y_node_Map[mY].length; k++) {
            Y_node_Map[mY][k].position(
              Y_node_Map[mY][k].position().x + VIEW_WIDTH + SPACE_DISTANCE,
              Y_node_Map[mY][k].position().y
            )
          }
        }
        Y_node_Map[mY].splice(mIndex, 0, node)
      }
    } else {
      Y_node_Map[mY] = [node]
    }
  }
  const countNodeXY = (node, opt) => {
    let position = {
        x: 0,
        y: 0,
      },
      mY = -1,
      mX = -1
    if (!node) {
      position.x = midX
      position.y = midY
    } else {
      switch (opt) {
        case 'top':
          mY = node.position().y - VIEW_HEIGHT - SPACE_DISTANCE
          mX = node.position().x
          position.x = mX
          position.y = mY
          break
        case 'right':
          mY = node.position().y
          mX = node.position().x + VIEW_WIDTH + SPACE_DISTANCE
          position.x = mX
          position.y = mY
          break
        case 'bottom':
          mY = node.position().y + VIEW_HEIGHT + SPACE_DISTANCE
          mX = node.position().x
          position.x = mX
          position.y = mY
          break
      }
    }
    return position
  }
  const addEr = (node1, node2) => {
    mGraph.addEdge({
      source: node1.id,
      target: node2.id,
      connector: { name: 'smooth' },
      attrs: {
        line: {
          stroke: '#faad14',
          targetMarker: 'classic',
        },
      },
    })
  }
  const addWorkInProcessNode = (wipDataList, node, opt) => {
    wipDataList.forEach((wipData) => {
      let hasToBottom = opt === 'top' ? false : wipData.pkReport ? true : false,
        hasToRight = true,
        hasToTop = opt === 'bottom' ? false : wipData.pkReport ? true : false
      let newNode = nodeList.find(
        (nodeItem) => nodeItem.id === `wip_${wipData.pkReport}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }
      const position = countNodeXY(node, opt)
      newNode = mGraph.addNode({
        id: `wip_${wipData.pkReport}`,
        shape: 'work-in-progress',
        x: position.x,
        y: position.y,
        data: {
          wipData,
          hasToBottom,
          hasToRight,
          hasToTop,
          toTop: (mNode, topData) => {
            topData['wips'] &&
              topData['wips'].length > 0 &&
              addWorkInProcessNode(topData['wips'], mNode, 'top')
            topData['materials'] &&
              topData['materials'].length > 0 &&
              addMaterialNode(topData['materials'], mNode, 'top')
            mNode.setData({ hasToTop: false })
          },
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          toBottom: (mNode, bottomData) => {
            bottomData['wips'] &&
              bottomData['wips'].length > 0 &&
              addWorkInProcessNode(bottomData['wips'], mNode, 'bottom')
            bottomData['materials'] &&
              bottomData['materials'].length > 0 &&
              addMaterialNode(bottomData['materials'], mNode, 'bottom')
            bottomData['product'] &&
              bottomData['product'].length > 0 &&
              addProductNode(bottomData['product'], mNode, 'bottom')
            mNode.setData({ hasToBottom: false })
          },
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          toRight: (mNode, rightData) => {
            rightData['inspectionApplication'] &&
              rightData['inspectionApplication'].length > 0 &&
              addInspectionApplicationNode(
                rightData['inspectionApplication'],
                mNode,
                'right'
              )
            mNode.setData({ hasToRight: false })
          },
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }
  const addMaterialNode = (materialList, node, opt) => {
    materialList.forEach((materialData) => {
      let hasToBottom =
          opt === 'top' ? false : materialData.pkReport ? true : false,
        hasToRight = true,
        hasToTop =
          opt === 'bottom' ? false : materialData.pkReport ? true : false

      let newNode = nodeList.find(
        (nodeItem) => nodeItem.id === `material_${materialData.barcode}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }
      const position = countNodeXY(node, opt)
      newNode = mGraph.addNode({
        id: `material_${materialData.barcode}`,
        shape: 'material',
        x: position.x,
        y: position.y,
        data: {
          materialData,
          hasToBottom,
          hasToRight,
          hasToTop,
          toTop: (mNode, topData) => {
            topData['wips'] &&
              topData['wips'].length > 0 &&
              addWorkInProcessNode(topData['wips'], mNode, 'top')
            topData['materials'] &&
              topData['materials'].length > 0 &&
              addMaterialNode(topData['materials'], mNode, 'top')
            mNode.setData({ hasToTop: false })
          },
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          toBottom: (data) => {},
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          toRight: (data) => {},
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }

  const addWorkReport = (reportList, node, opt) => {
    reportList.forEach((reportData) => {
      let hasToBottom = opt === 'top' ? false : true,
        hasToRight = false,
        hasToTop = opt === 'bottom' ? false : true

      let newNode = nodeList.find(
        (nodeItem) => nodeItem.id === `work_report_${reportData.pkReport}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }

      const position = countNodeXY(node, opt)

      newNode = mGraph.addNode({
        id: `work_report_${reportData.pkReport}`,
        shape: 'workReport',
        x: position.x,
        y: position.y,
        data: {
          reportData,
          hasToBottom,
          hasToRight,
          hasToTop,
          toBottom: (mNode, bottomData) => {
            bottomData['products'] &&
              bottomData['products'].length > 0 &&
              addProductNode(bottomData['products'], mNode, 'bottom')
            mNode.setData({ hasToBottom: false })
          },
          toTop: (mNode, topData) => {
            topData['materials'] &&
              topData['materials'].length > 0 &&
              addMaterialNode(topData['materials'], mNode, 'top')
            topData['products'] &&
              topData['products'].length > 0 &&
              addProductNode(topData['products'], mNode, 'top')
            topData['wips'] &&
              topData['wips'].length > 0 &&
              addWorkInProcessNode(topData['wips'], mNode, 'top')
            mNode.setData({ hasToTop: false })
          },
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }

  const addProductNode = (productList, node, opt) => {
    productList.forEach((productData) => {
      let hasToBottom =
          opt === 'top'
            ? false
            : productData.invbatch && productData.pkWh
            ? true
            : false,
        hasToRight = false,
        hasToTop = false

      let newNode = nodeList.find(
        (nodeItem) => nodeItem.id === `product_${productData.pk_product_b}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }
      const position = countNodeXY(node, opt)
      newNode = mGraph.addNode({
        id: `product_${productData.pk_product_b}`,
        shape: 'product',
        x: position.x,
        y: position.y,
        data: {
          productData,
          hasToBottom,
          hasToRight,
          hasToTop,
          toBottom: (mNode, bottomData) => {
            bottomData['reports'] &&
              bottomData['reports'].length > 0 &&
              addWorkReport(bottomData['reports'], mNode, 'bottom')
            mNode.setData({ hasToTop: false })
          },
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }
  const addInspectionApplicationNode = (
    inspectionApplicationList,
    node,
    opt
  ) => {
    let hasToRight = true
    inspectionApplicationList.forEach((inspectionApplicationData) => {
      let newNode = nodeList.find(
        (nodeItem) =>
          nodeItem.id ===
          `inspectionApplicationData_${inspectionApplicationData.inspect_gx_code}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }
      const position = countNodeXY(node, opt)
      newNode = mGraph.addNode({
        id: `inspectionApplicationData_${inspectionApplicationData.inspect_gx_code}`,
        shape: 'inspection-application',
        x: position.x,
        y: position.y,
        data: {
          inspectionApplicationData,
          hasToRight,
          toRight: (mNode, rightData) => {
            rightData['inspectionSheet'] &&
              rightData['inspectionSheet'].length > 0 &&
              addInspectionSheetNode(
                rightData['inspectionSheet'],
                mNode,
                'right'
              )
            mNode.setData({ hasToRight: false })
          },
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }
  const addInspectionSheetNode = (inspectionSheetList, node, opt) => {
    let hasToRight = true
    inspectionSheetList.forEach((inspectionSheetData) => {
      let newNode = nodeList.find(
        (nodeItem) =>
          nodeItem.id ===
          `inspectionSheetData_${inspectionSheetData.check_gx_code}`
      )
      if (newNode) {
        if (node && newNode) {
          addEr(node, newNode)
        }
        return
      }
      const position = countNodeXY(node, opt)
      newNode = mGraph.addNode({
        id: `inspectionSheetData_${inspectionSheetData.check_gx_code}`,
        shape: 'inspection-sheet',
        x: position.x,
        y: position.y,
        data: {
          inspectionSheetData,
          hasToRight,
          toRight: (mNode) => {
            mNode.setData({ hasToRight: false })
          },
        },
      })
      if (newNode) {
        setNodeMap(newNode)
        nodeList.push(newNode)
      }
      if (node && newNode) {
        addEr(node, newNode)
      }
    })
  }

  // const showNodes = (mNode, data, opt) => {
  //   data['wips'] &&
  //     data['wips'].length > 0 &&
  //     addWorkInProcessNode(data['wips'], mNode, opt)

  //   data['materials'] &&
  //     data['materials'].length > 0 &&
  //     addMaterialNode(data['materials'], mNode, opt)
  // }
</script>

<style scoped>
  .zzpzhuisu-container {
    position: relative;
    padding: 0 !important;
  }
  .search-btn {
    position: absolute;
    top: 12px;
    left: 12px;
  }
  .plus-btn {
    position: absolute;
    bottom: 12px;
    left: 60px;
  }
  .sub-btn {
    position: absolute;
    bottom: 12px;
    left: 12px;
  }
  .x6-container {
    width: 100%;
    height: calc(100vh - 150px);
  }
</style>
